using System;
using System.Collections.Generic;
using System.Linq;
using Pay.Core;
using Pay.Data;
using Pay.DTO;
using Pay.IService;
using Pay.Service.Cache;
using Pay.TO;

namespace Pay.Service {
	public class BillService : ServiceBase, IBillService, IDisposable {
		private IUnitOfWork _iUnitOfWork;
		private ISettingService _iSettingService;
		private IMerchantService _iMerchantService;
		private IPaymentService _iPaymentService;

		public BillService(IUnitOfWork iUnitOfWork, ISettingService iSettingService, IMerchantService iMerchantService, IPaymentService iPaymentService)
			: base(iUnitOfWork) {
			_iUnitOfWork = iUnitOfWork;
			_iSettingService = iSettingService;
			_iMerchantService = iMerchantService;
			_iPaymentService = iPaymentService;
		}

		#region 查询账单
		/// <summary>
		/// 平台的账务
		/// </summary>
		/// <param name="pay_channel"></param>
		/// <returns></returns>
		public plat_bill_dto Get(PayChannel pay_channel) {
			var query = context.PlatBills.Where(c => c.PayChannel == pay_channel);
			var result = query.FromCacheFirstOrDefault<PlatBill, plat_bill_dto>("Bill0");

			if (result == null) {
				result = new plat_bill_dto { pay_channel = pay_channel };
			}
			return result;
		}

		/// <summary>
		/// 平台账单列表
		/// </summary>
		/// <param name="billQuery"></param>
		/// <returns></returns>
		public PagedResult<plat_bill_detail_dto> Get(BillQuery billQuery) {
			var filter = PredicateBuilder.True<PlatBillDetail>();
			filter = filter.And(c => c.PlatBill.PayChannel == billQuery.pay_channel);

			if (!string.IsNullOrEmpty(billQuery.order_no))
				filter = filter.And(c => c.PayInfo.OrderNo == billQuery.order_no);
			if (billQuery.bill_type != BillType.None)
				filter = filter.And(c => c.BillType == billQuery.bill_type);
			if (billQuery.status != BillStatus.None)
				filter = filter.And(c => c.Status == billQuery.status);
			else
				filter = filter.And(cw => cw.Status != BillStatus.None);
			if (!string.IsNullOrEmpty(billQuery.start_date) && !string.IsNullOrEmpty(billQuery.end_date))
				filter = filter.And(c => c.CreateTime >= DateTime.Parse(billQuery.start_date).ToUnix()
									&& c.CreateTime <= DateTime.Parse(billQuery.end_date).ToUnix());
			return context.PlatBillDetails.FromCachePaged<PlatBillDetail, plat_bill_detail_dto>(billQuery.page, billQuery.size, filter, orderBy => orderBy.OrderByDescending(c => c.Id),
					   "Bill0");
		}

		/// <summary>
		/// 平台的账单明细
		/// </summary>
		/// <returns>The get.</returns>
		/// <param name="id">Identifier.</param>
		public plat_bill_detail_dto Get(long id) {
			return context.PlatBillDetails.Where(c => c.Id == id).FromCacheFirstOrDefault<PlatBillDetail, plat_bill_detail_dto>("Bill0");
		}

		/// <summary>
		/// 获取所有平台账单列表
		/// </summary>
		/// <param name="billQuery"></param>
		/// <returns></returns>
		public PagedResult<bill_ex> GetBills(BillQueryEx billQuery) {
			var filter = PredicateBuilder.True<Bill>();
			if (!string.IsNullOrEmpty(billQuery.mobile))
				filter = filter.And(c => c.Merchant.Mobile == billQuery.mobile);
			if (!string.IsNullOrEmpty(billQuery.name))
				filter = filter.And(c => c.Merchant.Name == billQuery.name);
			if (!string.IsNullOrEmpty(billQuery.merchant_no))
				filter = filter.And(c => c.Merchant.MerchantNo == billQuery.merchant_no);
			if (billQuery.is_oem)
				filter = filter.And(c => c.Merchant.IsOEM == billQuery.is_oem);
			if (billQuery.merchant_id > 0)
				filter = filter.And(c => c.Merchant.OemId == billQuery.merchant_id);
			return context.Bills.FromCachePaged<Bill, bill_ex>(billQuery.page, billQuery.size, filter, orderBy => orderBy.OrderByDescending(c => c.Id), "Bill0");
		}

		/// <summary>
		/// 商户的账务
		/// </summary>
		/// <param name="merchant_id"></param>
		/// <returns></returns>
		public bill_dto GetByMerchant(long merchant_id) {
			var query = context.Bills.Where(c => c.MerchantId == merchant_id);// && c.PayChannel == pay_channel);
			var result = query.FirstOrDefault().ToDtoObject<bill_dto>();

			if (result == null) {
				result = new bill_dto { merchant_id = merchant_id };
			}
			return result;
		}

		/// <summary>
		/// 商户的账单列表
		/// </summary>
		/// <param name="billQuery"></param>
		/// <returns></returns>
		public PagedResult<bill_detail_dto> GetByMerchant(BillQuery billQuery) {
			var filter = PredicateBuilder.True<BillDetail>();
			if (billQuery.merchant_id > 0)
				filter = filter.And(c => c.Bill.MerchantId == billQuery.merchant_id);
			if (billQuery.pay_channel != PayChannel.None)
				filter = filter.And(c => c.PayInfo.PayChannel == billQuery.pay_channel);

			if (!string.IsNullOrEmpty(billQuery.order_no))
				filter = filter.And(c => c.PayInfo.OrderNo == billQuery.order_no);
			if (billQuery.bill_type != BillType.None)
				filter = filter.And(c => c.BillType == billQuery.bill_type);
			if (billQuery.bill_id != 0)
				filter = filter.And(c => c.BillId == billQuery.bill_id);
			if (billQuery.status != BillStatus.None)
				filter = filter.And(c => c.Status == billQuery.status);
			else
				filter = filter.And(cw => cw.Status != BillStatus.None);
			var startTime = DateTime.Now;
			if (!string.IsNullOrEmpty(billQuery.start_date) && !string.IsNullOrEmpty(billQuery.end_date)) {
				if (DateTime.TryParse(billQuery.start_date, out startTime) && DateTime.TryParse(billQuery.end_date, out startTime)) {
					var start_time = DateTime.Parse(billQuery.start_date);
					var end_time = DateTime.Parse(billQuery.end_date).AddDays(1);
					if (end_time > start_time) {
						filter = filter.And(c => c.CreateTime >= start_time.ToUnix()
						&& c.CreateTime <= end_time.ToUnix());
					}
				}
			}
			return context.BillDetails.FromCachePaged<BillDetail, bill_detail_dto>(billQuery.page, billQuery.size, filter, orderBy => orderBy.OrderByDescending(c => c.Id));
		}

		/// <summary>
		/// 商户的账单明细
		/// </summary>
		/// <returns>The get.</returns>
		/// <param name="id">Identifier.</param>
		public bill_detail_dto GetBillDetail(long id) {
			return context.BillDetails.Where(c => c.Id == id).FirstOrDefault().ToDtoObject<bill_detail_dto>();
		}

		public bill_dto GetBill(head_req model) {
			var query = context.Bills.Where(c => c.Merchant.MerchantNo == model.bind_no);
			var result = query.FirstOrDefault().ToDtoObject<bill_dto>();
			return result;
		}

		public PagedResult<bill_detail_dto> GetByBillDetail(bill_model model) {
			var query = _iMerchantService.Get(model.bind_no);
			var dto = model.ToDtoObject<BillQuery>();
			dto.merchant_id = query.id;
			return GetByMerchant(dto);
		}
		#endregion

		private DateTime _billDt;
		/// <summary>
		/// 商户账单
		/// </summary>
		private Dictionary<string, Bill> _merchant_accounts;
		private List<string> _uid_tags = new List<string>();
		private PlatBill _platBill;

		/// <summary>
		/// 新增商户账务,处理好不要重复新增相同用户的账单
		/// </summary>
		/// <param name="merchant_id"></param>
		/// <returns></returns>
		private Bill AddMerchantBill(long merchant_id) {
			string key = merchant_id.ToString();//+ "-" + channel.ToString();
			Bill account;
			if (_merchant_accounts.TryGetValue(key, out account))
				return account;
			//account = context.Bills.Where(c => c.MerchantId == merchant_id && c.PayChannel == channel).FirstOrDefault();
			account = context.Bills.Where(c => c.MerchantId == merchant_id).FirstOrDefault();
			if (account == null) {
				account = new Bill();
				//account.PayChannel = channel;
				account.MerchantId = merchant_id;
				context.Bills.Add(account);
				_merchant_accounts.Add(key, account);
			} else {
				//context.Entry(account).State = EntityState.Modified;
				_merchant_accounts.Add(key, account);
			}

			return account;
		}

		/// <summary>
		/// 平台账务
		/// </summary>
		/// <param name="channel">Channel.</param>
		private void AddPlatBill(PayChannel channel) {
			_platBill = context.PlatBills.FirstOrDefault(c => c.PayChannel == channel);
			if (_platBill == null) {
				_platBill = new PlatBill { PayChannel = channel };
				context.PlatBills.Add(_platBill);
			}
		}

		#region 隔天平台收款对账后生成的账务
		/// <summary>
		/// 支付平台账单
		/// </summary>
		/// <returns>The account.</returns>
		/// <param name="kj_dic">Orderdentifier.</param>
		/// <param name="df_dic">Transter identifier.</param>
		public int ChargeAccount(List<itp_model> kj_dic, Dictionary<string, decimal> df_dic, PayChannel payChannel, string code, profit_day_dto profit_day) {
			AddPlatBill(payChannel);
			_billDt = DateTime.Now;
			var error = new List<string>();
			decimal profit = 0;
			decimal day_fee = 0;
			decimal day_profit = 0;
			decimal d0_offpay = 0;
			decimal merchant_profit = 0;
			//只有非HF用
			decimal fee_cost = 0;
			//平台账单
			var payment = _iPaymentService.Get().First(c => c.channel == payChannel);
			var plat_mer_id = payment.merchant_id;
			profit_day.pay_count = kj_dic.Count;
			//收款
			foreach (var item in kj_dic) {
				var billDetails = context.BillDetails.Where(c => c.PayInfo.TransactionNo == item.transaction_no).ToList();
				if (billDetails.Count == 0) {
					error.Add(string.Format("交易单：{0}找不到", item.transaction_no));
					continue;
				}
				var charge = context.Charges.FirstOrDefault(c => c.PayInfo.TransactionNo == item.transaction_no);
				if (charge.PayAmount != item.tran_amount) {
					error.Add(string.Format("交易单：{0}支付金额不符合，订单号：{1}", item.transaction_no, charge.OrderNo));
					continue;
				}
				day_fee += charge.FeeAmount + charge.SettleFee;
				var feeBillDetails = billDetails.Where(c => (c.BillType == BillType.FeeProfit) && c.Bill.MerchantId != plat_mer_id);
				var mer_profit = feeBillDetails.Sum(c => (decimal?)c.Amount) ?? 0;
				merchant_profit += mer_profit;
				var billDetail = new PlatBillDetail();
				billDetail.CreateTime = _billDt.ToUnix();
				billDetail.ObjectId = charge.Id;
				billDetail.PayId = charge.PayId.Value;
				billDetail.Status = BillStatus.Finish;
				var cost_fee_amt = item.cost_fee_amt;
				if (item.cost_fee_amt == 0) {
					var settle = payment.settles.First(c => c.settle_type == "T0");
					cost_fee_amt = (decimal)((int)Math.Ceiling(charge.PayAmount * settle.fee * 100)) / 100M;
					fee_cost += cost_fee_amt;
				}
				billDetail.Amount = charge.PayAmount * charge.Fee - cost_fee_amt - mer_profit;
				billDetail.BillType = BillType.FeeProfit;
				if (charge.PayInfo.SettleType == "T0") {
					var settleBillDetail = billDetails.FirstOrDefault(c => c.Bill.MerchantId == plat_mer_id && c.BillType == BillType.SettleProfit);
					if (settleBillDetail != null)
						billDetail.Amount += settleBillDetail.Amount;
					settleBillDetail = billDetails.FirstOrDefault(c => c.Bill.MerchantId != plat_mer_id && c.BillType == BillType.SettleProfit);
					if (settleBillDetail != null)
						merchant_profit += settleBillDetail.Amount;
					d0_offpay += charge.Amount;
					if (item.off_amount > 0 && charge.Amount != item.off_amount) {
						error.Add(string.Format("交易单：{0}代付金额不符合，订单号：{1}", item.transaction_no, charge.OrderNo));
						continue;
					}
				}
				profit += billDetail.Amount;
				_platBill.Balance += billDetail.Amount;
				billDetail.PlatBill = _platBill;
				billDetail.Balance = _platBill.Balance;
				if (error.Count == 0)
					context.PlatBillDetails.Add(billDetail);


				//var groupDetails = billDetails.GroupBy(c => c.PayId);
				//foreach (var groupDetail in groupDetails) {
				//	var charge = context.Charges.FirstOrDefault(c => c.PayId == groupDetail.Key);
				//	if (charge.PayAmount != item.tran_amount) {
				//		error.Add(string.Format("交易单：{0}支付金额不符合，订单号：{1}", item.transaction_no, charge.OrderNo));
				//		continue;
				//	}
				//	day_fee += charge.FeeAmount + charge.SettleFee;
				//	var feeBillDetails = groupDetail.Where(c => (c.BillType == BillType.FeeProfit) && c.Bill.MerchantId != plat_mer_id);
				//	var mer_profit = feeBillDetails.Sum(c => (decimal?)c.Amount) ?? 0;
				//	merchant_profit += mer_profit;
				//	var billDetail = new PlatBillDetail();
				//	billDetail.CreateTime = _billDt.ToUnix();
				//	billDetail.ObjectId = charge.Id;
				//	billDetail.PayId = groupDetail.Key;
				//	billDetail.Status = BillStatus.Finish;
				//	var cost_fee_amt = item.cost_fee_amt;
				//	if (item.cost_fee_amt == 0) {
				//		var settle = payment.settles.First(c => c.settle_type == "T0");
				//		cost_fee_amt = (decimal)((int)Math.Ceiling(charge.PayAmount * settle.fee * 100)) / 100M;
				//		fee_cost += cost_fee_amt;
				//	}
				//	billDetail.Amount = charge.PayAmount * charge.Fee - cost_fee_amt - mer_profit;
				//	billDetail.BillType = BillType.FeeProfit;
				//	if (charge.PayInfo.SettleType == "T0") {
				//		var settleBillDetail = groupDetail.FirstOrDefault(c => c.Bill.MerchantId == plat_mer_id && c.BillType == BillType.SettleProfit);
				//		if (settleBillDetail != null)
				//			billDetail.Amount += settleBillDetail.Amount;
				//		settleBillDetail = groupDetail.FirstOrDefault(c => c.Bill.MerchantId != plat_mer_id && c.BillType == BillType.SettleProfit);
				//		if (settleBillDetail != null)
				//			merchant_profit += settleBillDetail.Amount;
				//		d0_offpay += charge.Amount;
				//		if (item.off_amount > 0 && charge.Amount != item.off_amount) {
				//			error.Add(string.Format("交易单：{0}代付金额不符合，订单号：{1}", item.transaction_no, charge.OrderNo));
				//			continue;
				//		}
				//	}
				//	profit += billDetail.Amount;
				//	_platBill.Balance += billDetail.Amount;
				//	billDetail.PlatBill = _platBill;
				//	billDetail.Balance = _platBill.Balance;
				//	if (error.Count == 0)
				//		context.PlatBillDetails.Add(billDetail);
				//}
			}
			//提现
			foreach (var item in df_dic) {
				var billDetails = context.BillDetails.Where(c => c.PayInfo.TransactionNo == item.Key).ToList();
				var groupDetails = billDetails.GroupBy(c => c.PayId);
				foreach (var groupDetail in groupDetails) {
					var transfer = context.Transfers.FirstOrDefault(c => c.PayId == groupDetail.Key);
					if (transfer.SettleAmount == 0) continue;
					var feeBillDetails = groupDetail.Where(c => c.BillType == BillType.SettleProfit && c.Bill.MerchantId != plat_mer_id);
					var mer_profit = feeBillDetails.Sum(c => (decimal?)c.Amount) ?? 0;
					merchant_profit += mer_profit;
					var billDetail = new PlatBillDetail();
					billDetail.CreateTime = _billDt.ToUnix();
					billDetail.ObjectId = transfer.Id;
					billDetail.PayId = groupDetail.Key;
					billDetail.Status = BillStatus.Finish;
					billDetail.Amount = transfer.SettleAmount - item.Value - mer_profit;
					billDetail.BillType = BillType.SettleProfit;
					profit += billDetail.Amount;
					day_profit += transfer.SettleAmount - item.Value;
					_platBill.Balance += billDetail.Amount;
					billDetail.PlatBill = _platBill;
					billDetail.Balance = _platBill.Balance;
					context.PlatBillDetails.Add(billDetail);
				}
			}

			profit_day.profit = profit;
			profit_day.merchant_profit = merchant_profit;
			var log = IocHelper.Get<ILogHelper>("info");
			if (error.Count > 0) {
				foreach (var item in error)
					log.Info(item);
				throw new ServerErrorException(error.Aggregate((x, y) => x + "\r\n" + y), 1005);
			}
			if (payChannel == PayChannel.HxData) {
				if (profit_day.off_amount != d0_offpay) {
					log.Info("通道：" + profit_day.off_amount + ",平台：" + d0_offpay);
					throw new ServerErrorException("代付金额不正确", 1005);
				}
			} else
				profit_day.off_amount += d0_offpay;
			if (profit_day.fee_cost == 0 && fee_cost > 0)
				profit_day.fee_cost = fee_cost;
			profit_day.balance = _platBill.ChannelBalance + profit_day.pay_amount - profit_day.off_amount - profit_day.fee_cost;
			profit_day.status = 2;
			profit_day.day_profit = day_profit;
			_platBill.ChannelBalance = profit_day.balance;
			var model = context.ProfitDays.Find(profit_day.id);
			profit_day.ToDtoObject(model);
			int result = _iUnitOfWork.Commit("Bill0", "ProfitDay");
			return result;
		}
		#endregion


		#region 隔天平台收款对账后生成的账务
		/// <summary>
		/// 支付平台账单
		/// </summary>
		/// <returns>The account.</returns>
		/// <param name="kj_dic">Orderdentifier.</param>
		/// <param name="df_dic">Transter identifier.</param>
		public int HFChargeAccount(List<itp_model> kj_dic, Dictionary<string, decimal> df_dic, PayChannel payChannel, string code, profit_day_dto profit_day) {
			AddPlatBill(payChannel);
			_billDt = DateTime.Now;
			var error = new List<string>();
			decimal profit = 0;
			decimal day_settlefee = 0;
			decimal day_profit = 0;
			decimal d0_offpay = 0;
			decimal merchant_profit = 0;
			decimal balance = 0;
			//平台账单
			var payment = _iPaymentService.Get().First(c => c.channel == payChannel);
			var plat_mer_id = payment.merchant_id;
			profit_day.pay_count = kj_dic.Count;
			//收款
			foreach (var item in kj_dic) {
				var billDetails = context.BillDetails.Where(c => c.PayInfo.TransactionNo == item.transaction_no).ToList();
				if (billDetails.Count == 0) {
					error.Add(string.Format("交易单：{0}找不到", item.transaction_no));
					continue;
				}
				var charge = context.Charges.FirstOrDefault(c => c.PayInfo.TransactionNo == item.transaction_no);
				if (charge.PayAmount != item.tran_amount) {
					error.Add(string.Format("交易单：{0}支付金额不符合，订单号：{1}", item.transaction_no, charge.OrderNo));
					continue;
				}
				var feeBillDetails = billDetails.Where(c => (c.BillType == BillType.FeeProfit) && c.Bill.MerchantId != plat_mer_id);
				var mer_profit = feeBillDetails.Sum(c => (decimal?)c.Amount) ?? 0;
				merchant_profit += mer_profit;
				var billDetail = new PlatBillDetail();
				billDetail.CreateTime = _billDt.ToUnix();
				billDetail.ObjectId = charge.Id;
				billDetail.PayId = charge.PayId.Value;
				billDetail.Status = BillStatus.Finish;
				var fee_amt = Math.Round(charge.PayAmount * charge.Fee, 2) - item.cost_fee_amt;
				day_profit += fee_amt;
				billDetail.Amount = fee_amt - mer_profit;
				billDetail.BillType = BillType.FeeProfit;
				if (charge.PayInfo.SettleType == "T0") {
					day_settlefee += charge.SettleFee;
					balance += fee_amt;
					balance += charge.SettleFee;
					var settleBillDetail = billDetails.FirstOrDefault(c => c.Bill.MerchantId == plat_mer_id && c.BillType == BillType.SettleProfit);
					if (settleBillDetail != null)
						billDetail.Amount += settleBillDetail.Amount;
					settleBillDetail = billDetails.FirstOrDefault(c => c.Bill.MerchantId != plat_mer_id && c.BillType == BillType.SettleProfit);
					if (settleBillDetail != null)
						merchant_profit += settleBillDetail.Amount;
					//d0_offpay += charge.Amount;
					if (item.off_amount > 0 && charge.Amount != item.off_amount) {
						error.Add(string.Format("交易单：{0}代付金额不符合，订单号：{1}", item.transaction_no, charge.OrderNo));
						continue;
					}
				} else {
					//t1是都留下了，只要减费率成本
					balance += charge.PayAmount - item.cost_fee_amt;
				}
				profit += billDetail.Amount;
				_platBill.Balance += billDetail.Amount;
				billDetail.PlatBill = _platBill;
				billDetail.Balance = _platBill.Balance;
				if (error.Count == 0)
					context.PlatBillDetails.Add(billDetail);
			}
			//提现
			foreach (var item in df_dic) {
				var billDetails = context.BillDetails.Where(c => c.PayInfo.TransactionNo == item.Key).ToList();
				var groupDetails = billDetails.GroupBy(c => c.PayId);
				foreach (var groupDetail in groupDetails) {
					var transfer = context.Transfers.FirstOrDefault(c => c.PayId == groupDetail.Key);
					if (transfer.SettleAmount == 0) continue;
					var feeBillDetails = groupDetail.Where(c => c.BillType == BillType.SettleProfit && c.Bill.MerchantId != plat_mer_id);
					var mer_profit = feeBillDetails.Sum(c => (decimal?)c.Amount) ?? 0;
					merchant_profit += mer_profit;
					var billDetail = new PlatBillDetail();
					billDetail.CreateTime = _billDt.ToUnix();
					billDetail.ObjectId = transfer.Id;
					billDetail.PayId = groupDetail.Key;
					billDetail.Status = BillStatus.Finish;
					billDetail.Amount = transfer.SettleAmount - item.Value - mer_profit;
					billDetail.BillType = BillType.SettleProfit;
					profit += billDetail.Amount;
					day_settlefee += transfer.SettleAmount - item.Value;
					balance += transfer.SettleAmount - item.Value;
					_platBill.Balance += billDetail.Amount;
					billDetail.PlatBill = _platBill;
					billDetail.Balance = _platBill.Balance;
					context.PlatBillDetails.Add(billDetail);
				}
			}

			profit_day.profit = profit;
			profit_day.merchant_profit = merchant_profit;
			var log = IocHelper.Get<ILogHelper>("info");
			if (error.Count > 0) {
				foreach (var item in error)
					log.Info(item);
				throw new ServerErrorException(error.Aggregate((x, y) => x + "\r\n" + y), 1005);
			}
			profit_day.off_amount += d0_offpay;
			profit_day.balance = _platBill.ChannelBalance + balance - profit_day.off_amount;
			profit_day.status = 2;
			profit_day.day_profit = day_profit;
			profit_day.day_fee = day_settlefee;
			_platBill.ChannelBalance = profit_day.balance;
			var model = context.ProfitDays.Find(profit_day.id);
			profit_day.ToDtoObject(model);
			int result = _iUnitOfWork.Commit("Bill0", "ProfitDay");
			return result;
		}
		#endregion

		#region 退款账务
		public IEnumerable<string> RefundAccount(string order_no, string transactionNo) {
			var order = context.RefundOrders.FirstOrDefault(c => c.OrderNo == order_no);
			order.PayInfo.TransactionNo = transactionNo;

			_platBill = context.PlatBills.FirstOrDefault(c => c.PayChannel == order.PayInfo.PayChannel);
			if (_platBill == null) {
				_platBill = new PlatBill { PayChannel = order.PayInfo.PayChannel };
				context.PlatBills.Add(_platBill);
			}
			_billDt = DateTime.Now;
			_merchant_accounts = new Dictionary<string, Bill>();
			RefundPlatAccount(order);
			RefundMerchantAccount(order);
			return _uid_tags;
		}

		/// <summary>
		/// 退款平台账单
		/// </summary>
		/// <param name="order">Order.</param>
		private void RefundPlatAccount(RefundOrder order) {
			var payment = _iPaymentService.Get().First(c => c.channel == order.PayInfo.PayChannel);
			var settle = payment.settles.FirstOrDefault(c => c.settle_type == order.PayInfo.SettleType && c.code == order.PayInfo.PayCode);

			var billDetail = new PlatBillDetail();
			billDetail.CreateTime = _billDt.ToUnix();
			billDetail.ObjectId = order.Id;
			billDetail.PayId = order.PayId.Value;
			billDetail.Status = BillStatus.Finish;
			billDetail.Amount = -order.Amount;
			billDetail.BillType = BillType.Refund;

			_platBill.Balance += billDetail.Amount;
			_platBill.Unconfirmed += billDetail.Amount;

			billDetail.PlatBill = _platBill;
			billDetail.Balance = _platBill.Balance;
			context.PlatBillDetails.Add(billDetail);

			_uid_tags.Add("Bill0");
		}

		/// <summary>
		/// 退款商户账单
		/// </summary>
		/// <param name="order">Order.</param>
		private void RefundMerchantAccount(RefundOrder order) {
			var billDetail = new BillDetail();
			billDetail.CreateTime = _billDt.ToUnix();
			billDetail.PayId = order.PayId.Value;
			billDetail.Status = BillStatus.Finish;
			billDetail.Amount = -order.Amount;
			billDetail.BillType = BillType.Refund;

			var account = AddMerchantBill(order.Order.MerchantId);
			account.Balance += billDetail.Amount;
			account.Unconfirmed += billDetail.Amount;

			billDetail.Bill = account;
			billDetail.Balance = account.Balance;
			context.BillDetails.Add(billDetail);

			_uid_tags.Add("Bill" + order.Order.MerchantId);
		}
		#endregion
		//T+1来对指定天的账单都对账，并计算出来分润和可提现的金额

		#region 转账
		private void PlatTransfer(Transfer model, TransferStatus status = TransferStatus.None) {
			var payment = _iPaymentService.Get().FirstOrDefault(c => c.channel == model.PayInfo.PayChannel);
			var settle = payment.settles.FirstOrDefault(c => c.settle_type == model.PayInfo.SettleType && c.code == model.PayInfo.PayCode);
			//提现
			var amount = model.TransferAmount;
			var billDetail = new PlatBillDetail();
			billDetail.CreateTime = _billDt.ToUnix();
			billDetail.ObjectId = model.Id;
			billDetail.PayId = model.PayId;
			billDetail.Amount = -amount;
			billDetail.BillType = BillType.Deposit;

			_platBill.Balance -= amount;
			_platBill.Unconfirmed -= amount;
			if (status == TransferStatus.Finish) {
				billDetail.Status = BillStatus.Finish;
				_platBill.Deposited += amount;
			} else {
				billDetail.Status = BillStatus.Proceed;
				_platBill.Depositeding += amount;
			}

			billDetail.PlatBill = _platBill;
			billDetail.Balance = _platBill.Balance;
			context.PlatBillDetails.Add(billDetail);
			//结算费
			if (settle.settle > 0) {
				amount = settle.settle;
				billDetail = new PlatBillDetail();
				billDetail.CreateTime = _billDt.ToUnix();
				billDetail.ObjectId = model.Id;
				billDetail.PayId = model.PayId;
				billDetail.Amount = -amount;
				billDetail.BillType = BillType.OemTradeFee;

				_platBill.Balance -= amount;
				_platBill.Unconfirmed -= amount;
				if (status == TransferStatus.Finish) {
					billDetail.Status = BillStatus.Finish;
					_platBill.Deposited += amount;
				} else {
					billDetail.Status = BillStatus.Proceed;
					_platBill.Depositeding += amount;
				}

				billDetail.PlatBill = _platBill;
				billDetail.Balance = _platBill.Balance;
				context.PlatBillDetails.Add(billDetail);
			}
			_uid_tags.Add("Bill0");
		}

        /// <summary>
        /// 取消转账
        /// </summary>
        /// <returns>The transfer.</returns>
        /// <param name="order_no">Order no.</param>
        //public IEnumerable<string> Transfer(string order_no) {
        //	var model = context.Transfers.FirstOrDefault(c => c.OrderNo == order_no);
        //	_billDt = DateTime.Now;
        //	_merchant_accounts = new Dictionary<string, Bill>();
        //	AddPlatBill(model.PayInfo.PayChannel);

        //	//原账单取消
        //	var platBillDetails = context.PlatBillDetails.Where(c => order_no == c.PayInfo.OrderNo);
        //	decimal amount = 0;
        //	platBillDetails.DataForEach(billDetail => {
        //		billDetail.Status = BillStatus.Cancel;
        //		amount += -billDetail.Amount;
        //	});
        //	//增加回滚账单
        //	_platBill.Balance += amount;
        //	_platBill.Unconfirmed += amount;
        //	_platBill.Depositeding -= amount;

        //	var billDetails = context.BillDetails.Where(c => order_no == c.PayInfo.OrderNo);
        //	billDetails.DataForEach(billDetail => {
        //		billDetail.Status = BillStatus.Cancel;
        //		var account = billDetail.Bill;
        //		if (billDetail.BillType == BillType.Deposit) {
        //			var deposit = -billDetail.Amount;
        //			//增加回滚账单
        //			account.Balance += deposit;
        //			account.Deposit += deposit;
        //			account.Depositeding -= deposit;
        //		} else if (billDetail.BillType == BillType.SettleProfit) {
        //			var profit = billDetail.Amount;
        //			account.Balance -= profit;
        //			account.Unconfirmed -= profit;
        //		}
        //	});

        //	return _uid_tags;
        //}
        #endregion
         
        //钱包 分销收益和店铺收益
        public PagedResult<token_wallet_bill_detail_dto> GetWalletBillDetails(WalletQuery query) {
            var filter = PredicateBuilder.True<Profit>();
            filter = filter.And(c => !c.IsBus);
            filter = filter.And(c =>c.ProductId!=0);
            filter = filter.And(c => c.MerchantId == query.merchant_id);
            if (query.type == 1) {
                filter = filter.And(c =>c.BillType==BillType.Distribution);
            } else if (query.type == 3) {
                filter = filter.And(c => c.BillType == BillType.Mall);
            }
            if (query.status == 2) {
                filter = filter.And(c => c.BillStatus == BillStatus.Finish);
            } else {
                filter = filter.And(c => c.BillStatus != BillStatus.Finish);
            }
            
            var result = context.Profits.FromCachePaged<Profit, token_wallet_bill_detail_dto>(query.page, query.size, filter, orderBy => orderBy.OrderByDescending(c => c.CreateTime));
            if (result != null && result.rows != null && (query.type == 1 || query.type == 3)) {// 店铺、分销收益列表跳转地址
                foreach (var row in result.rows) {
                    row.link_url = t_RequestMethod.token_url + "MyOrder/DistributionOrderDetail?order_id=" + row.order_id;//跳转至买家订单详情
                }
            }
            return result;
        }

        /// <summary>
        /// 获取某用户某账单类型统计
        /// </summary>
        /// <param name="bill_id"></param>
        /// <param name="bill_type"></param>
        /// <returns></returns>
        public List<bill_detail_dto> GetBillDetail(long bill_id, BillType bill_type) {
            return context.BillDetails.Where(c => c.BillId == bill_id && c.BillType == bill_type).ToDtoList<bill_detail_dto>();
        }


        #region 供应商PC
        /// <summary>
        /// 获取账单明细
        /// </summary>
        /// <param name="merchant_id"></param>
        /// <param name="bill_type"></param>
        /// <returns></returns>
        public List<profit_dto> GetProfitList(long merchant_id, BillType bill_type) {
            return context.Profits.Where(c => c.MerchantId == merchant_id  && c.BillType == bill_type).ToDtoList<profit_dto>();
        }
        /// <summary>
        /// 获得账单明细列表
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public PagedResult<spc_token_bill_detail_dto> SPC_GetProfitList(WalletQuery query) {
            var filter = PredicateBuilder.True<Profit>();
            filter = filter.And(c => !c.IsBus);
            filter = filter.And(c => c.MerchantId == query.merchant_id);
            if (query.type == 1) {
                filter = filter.And(c => c.BillType == BillType.Distribution);
            } else if (query.type == 3) {
                filter = filter.And(c => c.BillType == BillType.Mall);
            }
            var result = context.Profits.FromCachePaged<Profit, spc_token_bill_detail_dto>(query.page, query.size, filter, orderBy => orderBy.OrderByDescending(c => c.CreateTime));
            return result;
        }
        #endregion
    }
}
